import os
import bz2
import time
import pickle
import fnmatch
import sqlite3
import requests
from contextlib import closing
from xml.dom.minidom import parse
import xml.dom.minidom


def dir_init(file_path_all):
    file_path_all = os.path.dirname(file_path_all)
    if not os.path.exists(file_path_all):
        print("初始化文件夹：", file_path_all)
        os.makedirs(file_path_all)


def download(file_url, save_path_dir):
    file_name = os.path.basename(file_url)
    file_path = os.path.join(save_path_dir, file_name)
    dir_init(file_path)
    try:
        with open(file_path, 'wb') as f:
            with closing(requests.get(file_url, stream=True)) as response:
                chunk_size = 1024  # 单次请求最大值
                content_size = int(response.headers['content-length'])  # 内容体总大小
                data_count = 0
                for data in response.iter_content(chunk_size=chunk_size):
                    f.write(data)
                    data_count = data_count + len(data)
                    now_jd = (data_count / content_size) * 100
        print("下载完成：", file_name)
        return file_path
    except Exception as e:
        print("下载失败：", file_name)
        return ""


def extract_file_from_bz2(file_path):
    if not os.path.exists(file_path):
        print("文件不存在：", file_path)
        return ""
    try:
        file = bz2.open(file_path, 'r')
        file_path_bz2 = file_path.rstrip(".bz2")
        with open(file_path_bz2, 'wb') as f:
            f.write(file.read())
        return file_path_bz2
    except Exception as e:
        print("解压失败：", file_path)
        return ""


def get_db(sql_path):
    return sqlite3.connect(sql_path)


def deal_select(sql, sql_path, db_conn=None):
    if db_conn is None:
        db_conn = get_db(sql_path)
    cursor = db_conn.cursor()
    cursor.execute(sql)
    rs = cursor.fetchall()
    return rs


def get_href_from_xml_file(file_path_xml):
    try:
        DOMTree = xml.dom.minidom.parse(file_path_xml)
        collection = DOMTree.documentElement
        for c in collection.getElementsByTagName("data"):
            if c.getAttribute("type") == "primary_db":
                return os.path.basename(c.getElementsByTagName("location")[0].getAttribute("href"))
    except Exception as e:
        print("读取链接失败：", e)
        return ""


def get_repo_info_sqlite(link_repo, save_path="/tmp/temp4rpm_parse"):
    # link_repo = "https://update.cs2c.com.cn/NS/V10/V10SP1/os/adv/lic/base/x86_64/"
    link_repo = link_repo.rstrip('/')
    link_repodata_xml = link_repo + "/repodata/repomd.xml"
    file_path_xml = download(link_repodata_xml, save_path)
    if not os.path.exists(file_path_xml):
        return {"status": False}
    link_repodata_sqlite_bz2 = get_href_from_xml_file(file_path_xml)
    if link_repodata_sqlite_bz2 == "":
        return {"status": False}
    link_repodata_sqlite_bz2 = link_repo + "/repodata/" + link_repodata_sqlite_bz2
    file_path_sqlite_bz2 = download(link_repodata_sqlite_bz2, save_path)
    if not os.path.exists(file_path_sqlite_bz2):
        return {"status": False}
    file_path_sqlite = extract_file_from_bz2(file_path_sqlite_bz2)
    repo_info = {
        "status": os.path.exists(file_path_sqlite),
        "link_repo": link_repo,
        "link_repodata_xml": link_repodata_xml,
        "link_repodata_sqlite_bz2": link_repodata_sqlite_bz2,
        "file_path_xml": file_path_xml,
        "file_path_sqlite_bz2": file_path_sqlite_bz2,
        "file_path_sqlite": file_path_sqlite
    }
    return repo_info


def get_link_repo_map():
    link_repo_map = {
        "【已发布】#V10SP1#x86_64+arch64#base": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/base/x86_64/",
        "【已发布】#V10SP1#x86_64+arch64#updates": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/updates/x86_64/",
        # "【已发布】#V10SP1#aarch64#base": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/base/aarch64/",
        # "【已发布】#V10SP1#aarch64#updates": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/updates/aarch64/",
        "【已发布】#V10SP1#loongarch64#base": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/base/loongarch64/",
        "【已发布】#V10SP1#loongarch64#updates": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/updates/loongarch64/",
        "【已发布】#V10SP1#mips64el#base": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/base/mips64el/",
        "【已发布】#V10SP1#mips64el#updates": "https://update.cs2c.com.cn/NS/V10/V10SP1.1/os/adv/lic/updates/mips64el/",
        "【已发布】#V10SP2#x86_64+arch64#base": "https://update.cs2c.com.cn/NS/V10/V10SP2/os/adv/lic/base/x86_64/",
        "【已发布】#V10SP2#x86_64+arch64#updates": "https://update.cs2c.com.cn/NS/V10/V10SP2/os/adv/lic/updates/x86_64/",
        # "【已发布】#V10SP2#aarch64#base": "https://update.cs2c.com.cn/NS/V10/V10SP2/os/adv/lic/base/aarch64/",
        # "【已发布】#V10SP2#aarch64#updates": "https://update.cs2c.com.cn/NS/V10/V10SP2/os/adv/lic/updates/aarch64/",
        "【Koji_237】#V10SP1#mips64el#v10-sp1.1-updates-build": "http://172.30.200.204:8237/kojifiles/repos/v10-sp1.1-updates-build/latest/mips64el/",
        "【Koji_238】#V10SP1#x86_64+arch64#v10-sp1.1-updates-build": "http://172.30.12.238/kojifiles/repos/v10-sp1.1-updates-build/latest/x86_64/",
        # "【Koji_238】#V10SP1#aarch64#v10-sp1.1-updates-build": "http://172.30.12.238/kojifiles/repos/v10-sp1.1-updates-build/latest/aarch64/",
        "【Koji_239】#V10SP1#loongarch64#v10-sp1-abi-3c5000-updates-build": "http://172.30.200.204:8239/kojifiles/repos/v10-sp1-abi-3c5000-updates-build/latest/loongarch64/",
        "【Koji_238】#V10SP2#x86_64+arch64#v10-sp2-updates-build": "http://172.30.12.238/kojifiles/repos/v10-sp2-updates-build/latest/x86_64/",
        # "【Koji_238】#V10SP2#aarch64#v10-sp2-updates-build": "http://172.30.12.238/kojifiles/repos/v10-sp2-updates-build/latest/aarch64/",
        "【Koji_238】#V10SP3#x86_64+arch64#v10-sp3-updates-build": "http://172.30.12.238/kojifiles/repos/v10-sp3-updates-build/latest/x86_64/",
        # "【Koji_238】#V10SP3#aarch64#v10-sp3-updates-build": "http://172.30.12.238/kojifiles/repos/v10-sp3-updates-build/latest/aarch64/",
        "【Koji_238】#V10SP3HOST#x86_64+arch64#v10-sp3-hostos-build": "http://172.30.12.238/kojifiles/repos/v10-sp3-hostos-build/latest/x86_64/",
        # "【Koji_238】#V10SP3HOST#aarch64#v10-sp3-hostos-build": "http://172.30.12.238/kojifiles/repos/v10-sp3-hostos-build/latest/aarch64/",
        "【Koji_239】#V10SP3#loongarch64#v10-sp3-updates-build": "http://172.30.200.204:8239/kojifiles/repos/v10-sp3-updates-build/latest/loongarch64/",
        "【Koji_242】#NS86#x86_64+arch64#ns8.6-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.6-updates-build/latest/x86_64/",
        # "【Koji_242】#NS86#aarch64#ns8.6-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.6-updates-build/latest/aarch64/",
        "【Koji_242】#NS82#x86_64+arch64#ns8.2-anoli-Plus-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.2-anoli-Plus-updates-build/latest/x86_64/",
        # "【Koji_242】#NS82#aarch64#ns8.2-anoli-Plus-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.2-anoli-Plus-updates-build/latest/aarch64/",
        "【Koji_242】#NS82#x86_64+arch64#ns8.2-anoli-BaseOS-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.2-anoli-BaseOS-updates-build/latest/x86_64/",
        # "【Koji_242】#NS82#aarch64#ns8.2-anoli-BaseOS-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.2-anoli-BaseOS-updates-build/latest/aarch64/",
        "【Koji_242】#NS82#x86_64+arch64#ns8.2-anoli-AppStream-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.2-anoli-AppStream-updates-build/latest/x86_64/",
        # "【Koji_242】#NS82#aarch64#ns8.2-anoli-AppStream-updates-build": "http://172.30.12.242/kojifiles/repos/ns8.2-anoli-AppStream-updates-build/latest/aarch64/",
    }
    for k in link_repo_map.keys():
        link_repo_map[k] = link_repo_map[k].rstrip('/')
    return link_repo_map


def get_repo_data():
    link_repo_map = get_link_repo_map()
    repo_info_map = {}
    for tag, link_repo in link_repo_map.items():
        repo_info_map[tag] = get_repo_info_sqlite(link_repo)
    return repo_info_map


def repo_info_map_save(repo_info_map, save_path="/tmp/temp4rpm_parse/dir_map"):
    try:
        with open(save_path, 'wb') as f:
            pickle.dump(repo_info_map, f)
    except Exception as e:
        print("保存repo_info_map失败", e)


def repo_info_map_load(save_path="/tmp/temp4rpm_parse/dir_map"):
    try:
        with open(save_path, 'rb') as f:
            repo_info_map = pickle.load(f)
            return repo_info_map
    except Exception as e:
        print("读取repo_info_map失败")
        return {}


def rpm_filter(rpm_name, _rpm_name):
    *_rpm_name_list, _, _ = _rpm_name.split('-')
    _rpm_name = '-'.join(_rpm_name_list)
    if '*' in rpm_name:
        return fnmatch.fnmatch(_rpm_name, rpm_name)
    return rpm_name == _rpm_name
    # return _rpm_name.startswith(rpm_name)


def search_rpm_from_sqlite(rpm_name, file_path_sqlite):
    try:
        sql_str = "select distinct rpm_sourcerpm from packages"
        #     sql_str = "select distinct arch from packages"
        group_all = [g_o[0] for g_o in deal_select(sql_str, file_path_sqlite)]
        rpm_all = [_rpm_name for _rpm_name in group_all if rpm_filter(rpm_name, _rpm_name.rstrip(".src.rpm"))]
        return rpm_all
    except Exception as e:
        print("数据库查询出错：", e)
        return ["数据库出错"]


def search_rpm_version(rpm_name, repo_info_map):
    rpm_repo_info = {}
    for tag, repo_info in repo_info_map.items():
        rpm_repo_info[tag] = search_rpm_from_sqlite(rpm_name, repo_info.get("file_path_sqlite"))
    return rpm_repo_info


if __name__ == '__main__':
    print("抓取时间：", time.strftime("%Y-%m-%d %H:%M:%S"))
    repo_info_map_save(get_repo_data())
    # repo_info_map = repo_info_map_load()
    # print(search_rpm_version("rpm", repo_info_map))
